<?php


namespace TDEngineOrm;

use support\Log;
use TDengine\Connection as TDConnection;
use TDEngineOrm\TDEngine;
abstract class Connection
{
    /** @var PDOStatement PDO操作实例 */
    protected $TDStatement;

    /** @var string 当前SQL指令 */
    protected $queryStr = '';
    // 返回或者影响记录数
    protected $numRows = 0;
    // 事务指令数
    protected $transTimes = 0;
    // 错误信息
    protected $error = '';

    /** @var PDO[] 数据库连接ID 支持多个连接 */
    protected $links = [];

    /** @var PDO 当前连接ID */
    protected $linkID;
    protected $linkRead;
    protected $linkWrite;


    // 监听回调
    protected static $event = [];
    // 使用Builder类
    protected $builder;
    // 数据库连接参数配置
    protected $config = [
        // 数据库类型
        'type'     => '',
        // 主机地址
        'hostname' => '',
        // 用户名
        'username' => '',
        // 数据库名
        'database' => '',

        'password'=>'',

        'port'=>'6030',
        // 数据库编码默认采用utf8
        'charset'  => 'utf8',
        // 数据库表前缀
        'prefix'   => '',
        // 数据库调试模式
        'debug'    => true,
        // Builder类
        'builder'         => '',
        // Query类
        'query'           => '\\TDEngineOrm\\Query',
        // 是否需要断线重连
        'break_reconnect' => false,
    ];

    /**
     * 构造函数 读取数据库配置信息
     * @access public
     * @param array $config 数据库配置数组
     */
    public function __construct(array $config = [])
    {

        if (!empty($config)) {
            $this->config = array_merge($this->config, $config);
        }
    }

    /**
     * 获取新的查询对象
     * @access protected
     * @return Query
     */
    protected function getQuery()
    {
        $class = $this->config['query'];
        return new $class($this);
    }
    /**
     * 获取当前连接器类对应的Builder类
     * @access public
     * @return string
     */
    public function getBuilder()
    {
        if (!empty($this->builder)) {
            return $this->builder;
        } else {
            return $this->getConfig('builder') ?: '\\TDEngineOrm\\builder\\' . ucfirst($this->getConfig('type'));
        }
    }

    /**
     * 调用Query类的查询方法
     * @access public
     * @param string    $method 方法名称
     * @param array     $args 调用参数
     * @return mixed
     */
    public function __call($method, $args)
    {
        return call_user_func_array([$this->getQuery(), $method], $args);
    }

    /**
     * 获取数据库的配置参数
     * @access public
     * @param string $config 配置名称
     * @return mixed
     */
    public function getConfig($config = '')
    {

        return $config ? $this->config[$config] : $this->config;
    }

    /**
     * 设置数据库的配置参数
     * @access public
     * @param string|array      $config 配置名称
     * @param mixed             $value 配置值
     * @return void
     */
    public function setConfig($config, $value = '')
    {
        if (is_array($config)) {
            $this->config = array_merge($this->config, $config);
        } else {
            $this->config[$config] = $value;
        }
    }
    /**
     * 获取PDO对象
     * @access public
     *
     */
    public function getTd()
    {
        if (!$this->linkID) {
            return false;
        } else {
            return $this->linkID;
        }
    }
    /**
     * 连接数据库方法
     * @access public
     * @param array         $config 连接参数
     * @param integer       $linkNum 连接序号
     * @param array|bool    $autoConnection 是否自动连接主数据库（用于分布式）
     *
     * @throws Exception
     */
    public function connect(array $config = [], $linkNum = 0, $autoConnection = false)
    {
        if (!isset($this->links[$linkNum])) {
            if (!$config) {
                $config = $this->config;
            } else {
                $config = array_merge($this->config, $config);
            }
            $db=$config['database'];
//            // 数据返回类型
//            if (isset($config['result_type'])) {
//                $this->fetchType = $config['result_type'];
//            }
            try {
               $connection = new TDConnection($config['hostname'], $config['port'], $config['username'], $config['password'],'' === $db ? null : $db);
               $this->links[$linkNum]=$connection->connect();

//                if ($config['debug']) {
//                    // 记录数据库连接信息
//                    Log::record('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn'], 'sql');
//                }
            } catch (\Exception $e) {
                if ($autoConnection) {
                   // Log::record($e->getMessage(), 'error');
                    return $this->connect($autoConnection, $linkNum);
                } else {
                    Log::info("[ DB ] CONNECT ERROR:'{$e->getMessage()}')");
                    throw $e;
                }
            }
        }
        return $connection;
        //return $this->links[$linkNum];
    }
    /**
     * 执行查询 返回数据集
     * @access public
     * @param string        $sql sql指令
     * @param array         $bind 参数绑定
     * @param bool          $master 是否在主服务器读操作
     * @param bool          $pdo 是否返回PDO对象
     * @return mixed
     * @throws PDOException
     * @throws \Exception
     */
    public function query($sql, $bind = [], $master = false, $pdo = false)
    {
        $this->initConnect($master);
        if (!$this->linkID) {
            return false;
        }
        // 记录SQL语句
        $this->queryStr = $sql;
        TDEngine::$queryTimes++;
        try {
            // 执行查询
            $resource = $this->connect()->query($sql);
            $result=$resource->fetch();
            $resource->close();
            // 返回结果集
            return $result;
        } catch (\Exception $e) {
            return $this->connect()->close();
            throw $e;
        }
    }
    public function selectDb($dbname){

        return $this->connect()->selectDb($dbname);
    }

    public function getDb(){
        return $this->connect()->getDb();
    }


    /**
     *
     * @DESC:获取数据库表的字段列表
     * @email:710388898@qq.com
     * @param $tableName
     * @author: 杨同师
     * @Time: 2022/9/9   11:18
     */
    public function getFields($tableName){
        $returnFields=[];
        // 执行查询
        $sql='desc '.$tableName;
        try{
            $this->connect()->query($sql);
            $field=$this->connect()->query($sql)->fetch();
            foreach ($field as $k=>$v){
                $returnFields[$v['Field']]['Field']=$v['Field'];
                $returnFields[$v['Field']]['Type']=$v['Type'];
                $returnFields[$v['Field']]['Length']=$v['Length'];
                $returnFields[$v['Field']]['Note']=$v['Note'];
            }
            return $returnFields;
        }catch (\Exception $e){
            return $returnFields;
        }

    }
    /**
     * 根据参数绑定组装最终的SQL语句 便于调试
     * @access public
     * @param string    $sql 带参数绑定的sql语句
     * @param array     $bind 参数绑定列表
     * @return string
     */
    public function getRealSql($sql,$bind=[])
    {
        if (is_array($sql)) {
            $sql = implode(';', $sql);
        }

        foreach ($bind as $key => $val) {
            $value = is_array($val) ? $val[0] : $val;
            $type  = is_array($val) ? $val[1] : PDO::PARAM_STR;
            if (PDO::PARAM_STR == $type) {
                $value = $this->quote($value);
            } elseif (PDO::PARAM_INT == $type) {
                $value = (float) $value;
            }
            // 判断占位符
            $sql = is_numeric($key) ?
                substr_replace($sql, $value, strpos($sql, '?'), 1) :
                str_replace(
                    [':' . $key . ')', ':' . $key . ',', ':' . $key . ' ', ':' . $key . PHP_EOL],
                    [$value . ')', $value . ',', $value . ' ', $value . PHP_EOL],
                    $sql . ' ');
        }
        return rtrim($sql);
    }

    /**
     * 获取最近一次查询的sql语句
     * @access public
     * @return string
     */
    public function getLastSql()
    {
        return $this->getRealSql($this->queryStr);
    }
    /**
     * 获得数据集数组
     * @access protected
     * @param bool   $pdo 是否返回PDOStatement
     * @param bool   $procedure 是否存储过程
     *
     */
    protected function getResult()
    {

        $result        =  $this->connect()->fetch();
        $this->numRows = count($result);
        return $result;
    }
    /**
     * 关闭数据库（或者重新连接）
     * @access public
     * @return $this
     */
    public function close()
    {
        $this->linkID    = null;
        $this->linkWrite = null;
        $this->linkRead  = null;
        $this->links     = [];
        // 释放查询

        return $this;
    }
    /**
     * 初始化数据库连接
     * @access protected
     * @param boolean $master 是否主服务器
     * @return void
     */
    protected function initConnect($master = true)
    {
        if (!$this->linkID) {
            // 默认单数据库
            $this->linkID = $this->connect();
        }
    }
    /**
     * 析构方法
     * @access public
     */
    public function __destruct()
    {

        // 关闭连接
        $this->close();
    }
}